package com.bandaotixi.cashier.api.business;

import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.bandaotixi.cashier.api.business.bo.CaptchaInfo;
import com.bandaotixi.cashier.api.common.enums.CaptchaTypeEnum;
import com.bandaotixi.cashier.api.common.model.KeyValue;
import com.bandaotixi.cashier.api.config.property.CaptchaProperties;
import com.bandaotixi.cashier.api.core.mybatis.SqlUtil;
import com.bandaotixi.cashier.api.system.model.Menu;
import com.bandaotixi.cashier.api.system.model.Role;
import com.bandaotixi.cashier.api.system.model.User;
import com.bandaotixi.cashier.api.system.service.MenuService;
import com.bandaotixi.cashier.api.system.service.RoleService;
import com.bandaotixi.cashier.api.system.service.SysKeyValueService;
import com.bandaotixi.cashier.api.system.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 认证服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthService implements StpInterface {

    private final java.awt.Font captchaFont;
    private final CaptchaProperties captchaProperties;
    private final CodeGenerator codeGenerator;
    private final UserService userService;
    private final MenuService menuService;
    private final RoleService roleService;
    private final SysKeyValueService keyValueService;

    /**
     * 用户名密码登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 访问令牌
     */
    public String login(String username, String password) {
        User user = userService.lambdaQuery().eq(User::getUsername, username).one();
        Assert.notNull(user, "账号或密码错误");
        Assert.isTrue(BCrypt.checkpw(password, user.getPassword()), "账号或密码错误");
        StpUtil.login(user.getId());
        return StpUtil.getTokenValue();
    }

    /**
     * 注销登录
     */
    public void logout() {
        StpUtil.logout();
    }

    /**
     * 获取验证码
     *
     * @return 验证码
     */
    public CaptchaInfo getCaptcha() {

        String captchaType = captchaProperties.getType();
        int width = captchaProperties.getWidth();
        int height = captchaProperties.getHeight();
        int interfereCount = captchaProperties.getInterfereCount();
        int codeLength = captchaProperties.getCode().getLength();

        AbstractCaptcha captcha;
        if (CaptchaTypeEnum.CIRCLE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.GIF.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength);
        } else if (CaptchaTypeEnum.LINE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.SHEAR.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount);
        } else {
            throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
        }
        captcha.setGenerator(codeGenerator);
        captcha.setTextAlpha(captchaProperties.getTextAlpha());
        captcha.setFont(captchaFont);

        String captchaCode = captcha.getCode();
        String imageBase64Data = captcha.getImageBase64Data();

        // 验证码文本缓存至Redis，用于登录校验
        String captchaKey = IdUtil.fastSimpleUUID();
        keyValueService.set(String.format("captcha:image:%s", captchaKey), captchaCode, captchaProperties.getExpireSeconds());
        return CaptchaInfo.builder()
                .captchaKey(captchaKey)
                .captchaBase64(imageBase64Data)
                .build();
    }

    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        List<KeyValue<Long, Long>> userRoleIds = SqlUtil.relational("sys_user_role", "role_id", "user_id", Map.of("user_id", loginId));
        Set<Long> roleIds = userRoleIds.stream().map(KeyValue::getKey).collect(Collectors.toSet());
        if (roleIds.contains(1L)) { // 管理员权限
            return List.of("*");
        }
        List<KeyValue<Long, Long>> roleMenuIds = SqlUtil.relational("sys_role_menu", "menu_id", "role_id", Map.of("role_id", roleIds));
        return menuService.lambdaQuery().in(Menu::getId, roleMenuIds.stream().map(KeyValue::getKey).toList()).list()
                .stream().map(Menu::getPerm).toList();
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        List<KeyValue<Long, Long>> userRoleIds = SqlUtil.relational("sys_user_role", "role_id", "user_id", Map.of("user_id", loginId));
        Set<Long> roleIds = userRoleIds.stream().map(KeyValue::getKey).collect(Collectors.toSet());
        if (roleIds.isEmpty()) {
            return List.of();
        }
        return roleService.lambdaQuery().in(Role::getId, roleIds).list()
                .stream().map(Role::getCode).toList();
    }
}
